package com.easyadmin.pro.modules.sys.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.easyadmin.pro.common.constants.HttpConstants;
import com.easyadmin.pro.common.constants.SystemConstants;
import com.easyadmin.pro.common.controller.BaseController;
import com.easyadmin.pro.common.enums.HttpCodeEnum;
import com.easyadmin.pro.common.exception.BusinessException;
import com.easyadmin.pro.common.exception.EasyAdminProBaseException;
import com.easyadmin.pro.common.page.Pageable;
import com.easyadmin.pro.common.vo.RestResult;
import com.easyadmin.pro.common.vo.RouterTree;
import com.easyadmin.pro.modules.sys.entity.UserEntity;
import com.easyadmin.pro.modules.sys.query.UserInfoQuery;
import com.easyadmin.pro.modules.sys.rest.UserInfoResultVo;
import com.easyadmin.pro.modules.sys.service.IUserService;
import com.easyadmin.pro.modules.sys.vo.*;
import com.easyadmin.pro.tool.RedisUtils;
import com.easyadmin.pro.tool.TokenUtils;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 *  控制层。
 *
 * @author 骑着蚂蚁去上天
 * @since 2024-04-01
 */
@RestController
@RequestMapping(HttpConstants.SYS_MODULE_PATH + "/user/")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserController extends BaseController {

    private final String USER_INFO_REDIS_KEY = "user-info-map";

    private final IUserService iUserService;

    @Resource
    private AuthenticationManager authenticationManager;

    /**
     * 登录
     * @return
     */
    @PostMapping("login")
    public RestResult login(@RequestBody LoginUserVo loginUserVo) {
        UsernamePasswordAuthenticationToken userInfo
                = new UsernamePasswordAuthenticationToken(loginUserVo.getUserName(), loginUserVo.getPassword());
        Authentication authenticate = authenticationManager.authenticate(userInfo);
        if (Objects.isNull(authenticate)) {
            throw new EasyAdminProBaseException(HttpCodeEnum.LOGIN_VERIFICATION_FAILURE);
        }
        UserVo userVo = (UserVo) authenticate.getPrincipal();
        UserEntity userEntity = userVo.getUserEntity();
        String token = TokenUtils.create(userEntity);
        Long userId = userEntity.getId();
        RedisUtils.setValueValidityPeriod(SystemConstants.LOGIN_PREFIX
                + userEntity.getId(), userEntity, 7, TimeUnit.DAYS.name());
        return success(HttpCodeEnum.LOGIN_SUCCESS.getMsg(),
                new LoginResultVo(token, userId,
                        JSONObject.parseArray(RedisUtils
                                .getValue(SystemConstants.ROUTER_KEY).toString(), RouterTree.class)));
    }

    /**
     * 登出
     * @param loginUserVo
     * @return
     */
    @PostMapping("logout")
    public RestResult logout(@RequestBody LoginUserVo loginUserVo) {
        String token = loginUserVo.getToken();
        Claims claims = TokenUtils.parse(token);
        if (Objects.isNull(claims)) {
            throw new EasyAdminProBaseException(HttpCodeEnum.TOKEN_PARSING_EXCEPTION);
        }
        loginUserVo.setUserName(claims.getSubject());
        UserEntity userInfo = iUserService.getOne(new QueryWrapper()
                .eq(UserEntity::getUserName, loginUserVo.getUserName()));
        if (Objects.isNull(userInfo)) {
            throw new EasyAdminProBaseException(HttpCodeEnum.USER_NOT_FOUND);
        }
        String redisKey = SystemConstants.LOGIN_PREFIX + userInfo.getId();
        RedisUtils.removeData(redisKey);
        return success(true);
    }

    /**
     * 注册接口
     * @param loginUserVo
     * @return
     */
    @PostMapping("register")
    public RestResult register(@RequestBody @Validated LoginUserVo loginUserVo) {
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(loginUserVo, userEntity);
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        userEntity.setPassword(bCryptPasswordEncoder.encode(userEntity.getPassword()));
        iUserService.saveOrUpdate(userEntity);
        Map<String, String> userInfoMap = (Map<String, String>) RedisUtils.getValue(USER_INFO_REDIS_KEY);
        userInfoMap.put(userEntity.getId().toString(), userEntity.getTrueName());
        RedisUtils.setHash(USER_INFO_REDIS_KEY, userInfoMap);
        return success(null);
    }

    /**
     * 修改用户信息
     * @param userInfoResultVo
     * @return
     */
    @PostMapping("modify")
    public RestResult changeUserInfo(@RequestBody @Validated UserInfoResultVo userInfoResultVo) {
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(userInfoResultVo, userEntity);
        iUserService.saveOrUpdate(userEntity);
        return success(null);
    }

    /**
     * 获取用户信息
     * @param userId
     * @return
     */
    @GetMapping("info/{userId}")
    public RestResult info(@PathVariable String userId) {
        UserInfoVo userInfo = iUserService.getUserInfo(userId);
        return success(userInfo);
    }

    /**
     * 添加。
     *
     * @param userEntity 
     * @return {@code true} 添加成功，{@code false} 添加失败
     */
    @PostMapping("save")
    public RestResult save(@RequestBody UserEntity userEntity) {
        return success(iUserService.save(userEntity));
    }

    /**
     * 根据主键删除。
     *
     * @param id 主键
     * @return {@code true} 删除成功，{@code false} 删除失败
     */
    @DeleteMapping("remove/{id}")
    public RestResult remove(@PathVariable Serializable id) {
        return success(iUserService.removeById(id));
    }

    /**
     * 根据主键更新。
     *
     * @param userEntity 
     * @return {@code true} 更新成功，{@code false} 更新失败
     */
    @PutMapping("update")
    public RestResult update(@RequestBody UserEntity userEntity) {
        return success(iUserService.updateById(userEntity));
    }

    /**
     * 查询所有。
     *
     * @return 所有数据
     */
    @GetMapping("list")
    public RestResult list() {
        return success(iUserService.list());
    }

    /**
     * 根据主键获取详细信息。
     *
     * @param id 主键
     * @return 详情
     */
    @GetMapping("getInfo/{id}")
    public RestResult getInfo(@PathVariable Serializable id) {
        UserInfoResultVo userInfoResultVo = new UserInfoResultVo();
        BeanUtils.copyProperties(iUserService.getById(id), userInfoResultVo);
        return success(userInfoResultVo);
    }

    /**
     * 分页查询。
     *
     * @param userInfoQuery 分页对象
     * @return 分页对象
     */
    @GetMapping("page")
    public RestResult page(UserInfoQuery userInfoQuery) {
        return success(Pageable.of(userInfoQuery, iUserService.queryUserInfo(userInfoQuery)));
    }

    /**
     * 返回用户信息
     * @return
     */
    @GetMapping("getUserInfos")
    public RestResult getUserInfos() {
        List<UserEntity> userEntities = iUserService.list();
        List<UserInfoResultVo> userInfos
                = com.easyadmin.pro.tool.BeanUtils.conventBeans(userEntities, UserInfoResultVo.class);
        return success(userInfos);
    }

    /**
     * 禁用用户
     * @param changeUserStatusVo
     * @return
     */
    @PostMapping("changeUserStatus")
    public RestResult changeUserStatus(@RequestBody @Validated ChangeUserStatusVo changeUserStatusVo) {
        Long userId = changeUserStatusVo.getUserId();
        UpdateChain.of(UserEntity.class).set(UserEntity::getStatus, changeUserStatusVo.getStatus())
                .eq(UserEntity::getId, userId).update();
        return success(HttpCodeEnum.SUCCESS.getCode(), "变更用户状态成功");
    }

    /**
     * 校验用户名
     * @param checkUserNameVo
     * @return
     */
    @PostMapping("checkUserName")
    public RestResult checkUserName(@RequestBody @Validated CheckUserNameVo checkUserNameVo) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(UserEntity::getUserName, checkUserNameVo.getUserName());
        if (Objects.nonNull(checkUserNameVo.getUserId())) {
            queryWrapper.ne(UserEntity::getId, checkUserNameVo.getUserId());
        }
        List<UserEntity> userEntities = iUserService.list(queryWrapper);
        if (CollectionUtil.isNotEmpty(userEntities)) {
            throw new BusinessException(HttpCodeEnum.USERNAME_EXIST);
        }
        return success();
    }

    /**
     * 获取用户名称
     * @param userId
     * @return
     */
    @GetMapping("getTrueName/{userId}")
    public RestResult getTrueName(@PathVariable String userId) {
        String trueName = "";
        if (StringUtils.hasLength(userId)) {
            Map<String, String> userInfoMap = (Map<String, String>) RedisUtils.getHash(USER_INFO_REDIS_KEY);
            trueName = userInfoMap.get(userId);
        }
        return success(trueName);
    }

}
